package com.lzy.securityResources.filter;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lzy.conf.JSONResult;
import com.lzy.conf.RsaKeyProperties;
import com.lzy.system.organization.entity.security.entity.SecurityUser;
import com.lzy.utils.JwtUtils;
import com.lzy.utils.Payload;
import com.lzy.utils.PublicVar;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.AntPathMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author Robod
 * @date 2020/8/10 8:42
 * 检验token过滤器
 */
public class JwtVerifyFilter extends BasicAuthenticationFilter {

    private long expire;
    private RsaKeyProperties rsaKeyProperties;

    public JwtVerifyFilter(AuthenticationManager authenticationManager, RsaKeyProperties rsaKeyProperties,long expire) {
        super(authenticationManager);
        this.rsaKeyProperties = rsaKeyProperties;
        this.expire = expire;
    }

    AntPathMatcher antPathMatcher = new AntPathMatcher();

    public void SC_FORBIDDEN(HttpServletResponse response, String msg) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        PrintWriter out = response.getWriter();
        out.write(new ObjectMapper().writeValueAsString(JSONResult.errorTokenMsg(msg)));
        out.flush();
        out.close();
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        String header = request.getHeader("Authorization");
        String requestURI = request.getRequestURI();
        for (String s : PublicVar.AUTH_WHITELIST) {
            if (antPathMatcher.match(s, requestURI)) {
                chain.doFilter(request, response);
                return;
            }
        }

        boolean isNotLogin = false;
        if (StrUtil.isBlank(header)) {
            header = request.getParameter("token");
            if (!StrUtil.isBlank(header)) {
                header = URLUtil.decode(header, "utf-8");
            }
        }
        if (StrUtil.isBlank(header) || !header.startsWith("lzy ")) {
            isNotLogin = true;
        }

        //没有登录
        if (isNotLogin) {
            SC_FORBIDDEN(response, "未登录");
            return;
        }
        //登录之后从token中获取用户信息
        String token = header.replace("lzy ", "");

        Payload payload = null;
        try {
            payload = JwtUtils.getInfoFromToken(token, rsaKeyProperties.getPublicKey(), SecurityUser.class);
        } catch (Exception e) {
            if (e instanceof ExpiredJwtException) {
                SC_FORBIDDEN(response, "token失效");
                return;
            } else {
                SC_FORBIDDEN(response, "token无效");
                return;
            }
        }

        if (payload != null) {
            SecurityUser userInfo = (SecurityUser) payload.getUserInfo();
            Authentication authResult = new UsernamePasswordAuthenticationToken
                    (userInfo, null, userInfo.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authResult);

            //决定是否续签 剩余十分钟还在操作 就续签
            long expiration_time = payload.getExpiration().getTime();
            long now_time = DateUtil.date().getTime();
            long minutesRemaining = (expiration_time - now_time) / 1000 / 60;
            Console.log("token过期时间:{}", DateUtil.format(payload.getExpiration(),"yyyy-MM-dd HH:mm:ss"));
            Console.log("token和现在相差分钟:{}", minutesRemaining);
            if(minutesRemaining<=30 && minutesRemaining>0){
                long time = expire;
                token = JwtUtils.generateTokenExpireInMinutes(userInfo, rsaKeyProperties.getPrivateKey(), (int) time);
                response.addHeader("Authorization", "lzy " + token);
            }
            chain.doFilter(request, response);
        }
    }
}
